package com.uzhie.jt808;

import com.google.common.base.Strings;
import com.uzhie.jt808.service.JT808PostService;
import com.uzhie.util.CacheManager;
import io.netty.channel.Channel;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by TangFei on 2018/8/19.
 * 808 Session 管理器
 */
public class JT808SessionManager {

    private Logger logger = Logger.getLogger(getClass());

    // 通道号 SIM号 对应关系
    @Autowired(required = false)
    private CacheManager<String, String> stringCacheManager;
    // SIM号 session 对应关系
    @Autowired(required = false)
    private CacheManager<String, JT808Session> sessionCacheManager;

    @Autowired
    private JT808PostService postService;

    // 缓存地址
    private final CacheManager.DES cacheDES;

    // 检测session周期
    // 默认 3分钟
    private long checkPeriod = 3 * 60 * 1000L;

    // 有效时长 单位：毫秒
    // 默认 10分钟
    private long expireTime = 10 * 60 * 1000L;

    private Timer timer;

    {
        cacheDES = CacheManager.DES.JT808_SESSION_CACHE;
        timer = new Timer("808SessionManagerThread", true);
    }

    public void init() {
        logger.trace("启动 808 session 管理器");
        scheduler();
    }

    public void destroy() {
        logger.trace("停止 808 session 管理器");
        timer.cancel();
    }

    public void setCheckPeriod(long checkPeriod) {
        this.checkPeriod = checkPeriod;
    }

    public void setExpireTime(long expireTime) {
        this.expireTime = expireTime;
    }

    /**
     * 刷新通道SIM卡号缓存
     *
     * @param channelID 通道ID
     * @param sim       SIM卡号
     */
    public void refreshChannelSimMap(String channelID, String sim) {
        stringCacheManager.put(cacheDES, channelID, sim);
    }

    /**
     * 刷新 SIM <---> session
     *
     * @param sim
     * @param channel
     * @param proto
     */
    public void refreshSimSession(String sim, Channel channel, JT808Session.PROTO proto) {
        JT808Session session = null;
        try {
            // 获取 sim-session
            session = sessionCacheManager.get(cacheDES, sim, JT808Session.class);
            logger.trace("当前session：" + session);
            if (null == session) {
                // 创建 sim-session
                session = new JT808Session(channel, expireTime);
            }
        } catch (NullPointerException e) {
            // 创建 sim-session
            session = new JT808Session(channel, expireTime);
        } finally {
            session.setChannel(channel);
            session.setProto(proto);
            session.refreshExpireAt(expireTime);
            // 建立 sim-session
            setSession(sim, session);
        }
    }

    /**
     * 刷新SIM卡号session缓存
     *
     * @param sim     SIM卡号
     * @param channel 通道实例
     */
    public void refreshSimSession(String sim, Channel channel) {
        JT808Session session = null;
        try {
            // 获取 sim-session
            session = sessionCacheManager.get(cacheDES, sim, JT808Session.class);
            logger.trace("当前session：" + session);
            if (null == session) {
                // 创建 sim-session
                session = new JT808Session(channel, expireTime);
            }
        } catch (NullPointerException e) {
            // 创建 sim-session
            session = new JT808Session(channel, expireTime);
        } finally {
            session.setChannel(channel);
            session.refreshExpireAt(expireTime);
            // 建立 sim-session
            setSession(sim, session);
        }
    }

    /**
     * 设置 session
     *
     * @param sim
     * @param session
     */
    public void setSession(String sim, JT808Session session) {
        sessionCacheManager.put(cacheDES, sim, session);
    }

    /**
     * 获取session
     *
     * @param sim
     * @return
     */
    public JT808Session getSession(String sim) {
        JT808Session session = sessionCacheManager.get(cacheDES, sim, JT808Session.class);
        return session;
    }

    private boolean isOverTime(JT808Session session) {
        if (System.currentTimeMillis() > session.getExpireAt()) {
            return true;
        } else {
            return false;
        }
    }

    private void scheduler() {
        TimerTask timerTask = new MyTimerTask();
        timer.scheduleAtFixedRate(timerTask, 2 * 60 * 1000L, checkPeriod);
    }

    /**
     * 任务类,用来清理已经超时的session数据
     */
    private class MyTimerTask extends TimerTask {
        @Override
        public void run() {
            logger.trace("正在检测 808session ......");
            List<String> sims = sessionCacheManager.getKeys(cacheDES);
            for (String sim : sims) {
                JT808Session session = sessionCacheManager.get(cacheDES, sim, JT808Session.class);
                if (session != null) {
                    logger.trace("SIM：" + sim + " 当前驾驶员信息：" + session.getDriverName());
                    if (isOverTime(session)) {
                        session.getChannel().close();
                        // 移除 sim-session
                        sessionCacheManager.remove(cacheDES, sim);
                        // 移除 channel-sim
                        stringCacheManager.remove(cacheDES, session.getChannel().id().asShortText());
                        logger.trace("移除成功 SIM：" + sim);
                    } else if (Strings.isNullOrEmpty(session.getDriverName())) {
                        logger.trace("下发驾驶员身份信息指令");
                        postService.post(JT808Constant.MSG_ID.PLA_REQ_DRIVER_INFO, sim, null);
                    }
                } else {
                    sessionCacheManager.remove(cacheDES, sim);
                }
            }
            logger.trace("检测 808session 结束");
        }
    }

}
